package cn.lingyangwl.agile.infra.file.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.lingyangwl.agile.infra.file.assembly.MaterialAssembly;
import cn.lingyangwl.agile.infra.file.modle.bo.FilePathBO;
import cn.lingyangwl.agile.infra.file.utils.FileUtils;
import cn.lingyangwl.agile.infra.module.file.constants.MaterialTypeEnum;
import cn.lingyangwl.agile.infra.file.mapper.MaterialMapper;
import cn.lingyangwl.agile.infra.module.file.model.entity.MediaMaterial;
import cn.lingyangwl.agile.infra.module.file.model.rqrs.*;
import cn.lingyangwl.agile.infra.file.service.MediaMaterialService;
import cn.lingyangwl.agile.infra.module.group.model.entity.DataGroup;
import cn.lingyangwl.agile.infra.module.group.model.rqrs.*;
import cn.lingyangwl.agile.infra.module.group.model.rqrs.DataGroupDto;
import cn.lingyangwl.agile.infra.group.service.DataGroupService;
import cn.lingyangwl.agile.model.constants.CommonCons;
import cn.lingyangwl.agile.model.enums.DataGroupBizTypeEnum;
import cn.lingyangwl.framework.mybatis.plus.utils.PageUtil;
import cn.lingyangwl.framework.tool.core.StringUtils;
import cn.lingyangwl.framework.tool.core.exception.BizException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 素材
 *
 * @author shenguangyang
 */
@Slf4j
@Service
public class MediaMaterialServiceImpl extends ServiceImpl<MaterialMapper, MediaMaterial>
    implements IService<MediaMaterial>, MediaMaterialService {
    @Resource
    private MaterialAssembly materialAssembly;
    @Resource
    private DataGroupService dataGroupService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteGroup(DataGroupDeleteReq req) {
        DataGroup firstGroup = dataGroupService.listByIds(req.getIds()).stream().findFirst()
                .orElseThrow(() -> new BizException("删除的数据不存在"));

        DataGroupQuery listReq = new DataGroupQuery();
        listReq.setBizType(DataGroupBizTypeEnum.MATERIAL.getType())
                .setGroupType(firstGroup.getGroupType())
                .setCode(CommonCons.DataGroup.DEFAULT_CODE);
        DataGroupDto defaultGroup = dataGroupService.listGroup(listReq).stream().findFirst()
                .orElseThrow(() -> new BizException("未查询到默认分组, 请联系管理员"));

        // 将被删除的组下面数据移动到默认分组下
        this.update(MediaMaterial.luw().set(MediaMaterial::getGroupId, defaultGroup.getId()).in(MediaMaterial::getGroupId, req.getIds()));
        return dataGroupService.deleteGroup(req);
    }

    @Override
    public IPage<MediaMaterialResp> pageMaterial(MediaMaterialPageReq req) {
        Set<Long> groupIds = new HashSet<>();
        groupIds.add(req.getGroupId());

        // 查询分组树的子节点
        List<DataGroupDto> groupList = dataGroupService.listChildrenGroup(req.getGroupId());
        groupIds.addAll(groupList.stream().map(DataGroupDto::getId).collect(Collectors.toList()));

        LocalDateTime beginTime = req.getBeginLocalDateTime();
        LocalDateTime endTime = req.getEndLocalDateTime();
        LambdaQueryWrapper<MediaMaterial> lqw = MediaMaterial.lqw()
            .eq(StringUtils.isNotEmpty(req.getType()), MediaMaterial::getType, req.getType())
            .in(MediaMaterial::getGroupId, groupIds)
            .like(StringUtils.isNotEmpty(req.getName()), MediaMaterial::getName, req.getName())
            .ge(Objects.nonNull(beginTime), MediaMaterial::getCreatedAt, beginTime)
            .le(Objects.nonNull(endTime), MediaMaterial::getCreatedAt, endTime)
            .orderByDesc(MediaMaterial::getCreatedAt);
        IPage<MediaMaterial> pageData = this.page(PageUtil.to(req), lqw);
        return PageUtil.to(pageData, e -> {
            MediaMaterialResp resp = materialAssembly.toMaterialResp(e);
            resp.setUrlSign(FileUtils.genUrlSign(resp.getUrl()));
            return resp;
        });
    }

    @Override
    public List<MediaMaterialResp> listMaterial(MediaMaterialListReq req) {
        List<String> fileRecordIds = req.getUrls().stream().map(url -> FilePathBO.parsePath(url).getFileRecordId())
            .collect(Collectors.toList());

        if (CollUtil.isEmpty(req.getIds()) && CollUtil.isEmpty(fileRecordIds)) {
            throw new BizException("文件id和url不能同时为空");
        }

        LambdaQueryWrapper<MediaMaterial> lqw = MediaMaterial.lqw()
            .in(CollUtil.isNotEmpty(req.getIds()), MediaMaterial::getId, req.getIds())
            .in(CollUtil.isNotEmpty(fileRecordIds), MediaMaterial::getFileRecordId, fileRecordIds);

        return this.list(lqw).stream().map(e -> {
            MediaMaterialResp resp = materialAssembly.toMaterialResp(e);
            resp.setUrlSign(FileUtils.genUrlSign(resp.getUrl()));
            return resp;
        }).collect(Collectors.toList());
    }

    @Override
    public MediaMaterialResp getMaterial(Long id) {
        MediaMaterial entity = this.getById(id);
        MediaMaterialResp resp = materialAssembly.toMaterialResp(entity);
        resp.setUrlSign(FileUtils.genUrlSign(resp.getUrl()));
        return resp;
    }

    @Override
    public boolean saveMaterial(MediaMaterialSaveReq req) {
        MaterialTypeEnum.checkExist(req.getType());
        MediaMaterial entity = materialAssembly.toMaterial(req);

        FilePathBO filePath = FilePathBO.parsePath(req.getUrl());
        entity.setFileRecordId(filePath.getFileRecordId());
    	return this.save(entity);
    }

    @Override
    public boolean updateMaterial(MediaMaterialUpdateReq req) {
        MediaMaterial entity = materialAssembly.toMaterial(req);
        FilePathBO filePath = FilePathBO.parsePath(req.getUrl());
        entity.setFileRecordId(filePath.getFileRecordId());
    	return this.updateById(entity);
    }

    @Override
    public boolean deleteMaterial(Long id) {
    	return this.removeById(id);
    }
    
    @Override
    public boolean batchDeleteMaterial(List<Long> ids) {
    	return this.removeByIds(ids);
    }
}
